package la.iok.hzsvn.lewin.movie.shopmovie.service;

import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import la.iok.hzsvn.lewin.movie.core.RoleEnum;
import la.iok.hzsvn.lewin.movie.core.Token;
import la.iok.hzsvn.lewin.movie.core.exception.ErrorCode;
import la.iok.hzsvn.lewin.movie.core.model.MovieVo;
import la.iok.hzsvn.lewin.movie.core.model.SimpleOrgUnitVo;
import la.iok.hzsvn.lewin.movie.core.movieservice.vo.MovieLevelVo;
import la.iok.hzsvn.lewin.movie.core.shopmovie.vo.ShopMovieVo;
import la.iok.hzsvn.lewin.movie.services.MovieServiceInvoker;
import la.iok.hzsvn.lewin.movie.shopmovie.entity.ShopMovie;
import la.iok.hzsvn.lewin.movie.shopmovie.mapper.ShopMovieMapper;
import la.iok.hzsvn.lewin.movie.shopmovie.model.ShopMovieListParam;
import la.iok.hzsvn.lewin.movie.shopmovie.model.ShopMovieModifyParam;
import la.iok.hzsvn.lewin.movie.shopmovie.model.ShopMovieParam;
import la.iok.hzsvn.lewin.mybatis.model.PageParam;
import la.iok.hzsvn.lewin.mybatis.model.PageVo;
import la.iok.hzsvn.lewin.mybatis.model.SortParam;
import la.iok.hzsvn.lewin.mybatis.service.BaseServiceImpl;
import la.iok.hzsvn.share.annotations.NotNull;
import la.iok.hzsvn.share.annotations.Nullable;
import la.iok.hzsvn.share.collection.IdOperators;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.stream.Collectors;

@Service
public class ShopMovieServiceImpl extends BaseServiceImpl<ShopMovie, ShopMovieMapper,Long> implements ShopMovieService {
    private final MovieServiceInvoker movieServiceInvoker;
    public ShopMovieServiceImpl(ShopMovieMapper mapper, MovieServiceInvoker movieServiceInvoker) {
        super(mapper);
        this.movieServiceInvoker = movieServiceInvoker;
    }

    @Override
    public Long save(@NotNull Token token, @NotNull ShopMovieParam param) {
        token.validAnyAuthority(RoleEnum.Admin,RoleEnum.Manager,RoleEnum.ShopManager);
        Long orgUnitId;
        if(token.hasAuthority(RoleEnum.Admin)){
            ErrorCode.PROPERTY_CHECK_ERROR.assertNotNull(param.getOrgUnitId(),"店铺","所属店铺不能为空");
            orgUnitId = param.getOrgUnitId();
        }else{
            ErrorCode.PROPERTY_CHECK_ERROR.assertNotNull(token.getOrgUnitId(),"用户","用户缺少组织信息");
            orgUnitId = token.getOrgUnitId();
        }
        SimpleOrgUnitVo orgUnit = movieServiceInvoker.orgUnitInfo(orgUnitId);
        ErrorCode.ORG_UNIT_NOT_EXIST.assertNotNull(orgUnit,orgUnitId);
        ErrorCode.PROPERTY_CHECK_ERROR.assertTrue(orgUnit.shopType(), "组织","只能是店铺才能执行此操作");
        ErrorCode.PROPERTY_CHECK_ERROR.assertTrue(orgUnit.normalStatus(),"店铺","店铺已经下线");
        MovieVo movie = movieServiceInvoker.movieInfo(param.getMovieId(),param.getMovieVersion());
        ErrorCode.MOVIE_NOT_EXIST.assertNotNull(movie,()->new Object[]{
                String.format("id:%d,version:%s",param.getMovieId(),param.getMovieVersion())
        });
        ErrorCode.PROPERTY_CHECK_ERROR.assertTrue(movie.statusOnline(),"剧本","剧本已经下线");
        ShopMovie entity = executeSelect("orgUnitId=" + orgUnitId + " and movieId=" + param.getMovieId() + " limit 1");
        ErrorCode.PROPERTY_CHECK_ERROR.assertNull(entity,"剧本","剧本[" + movie.getName()+"]已经存在");
        entity = new ShopMovie();
        BeanUtils.copyProperties(movie,entity);
        entity.setId(null);
        entity.setMovieId(param.getMovieId());
        entity.setOrgUnitId(orgUnitId);
        entity.setMovieVersion(param.getMovieVersion());
        entity.setMovieName(movie.getName());
        entity.setPlayTimes(0);
        entity.setTag(movie.storeTag());
        insertSelective(entity);
        return entity.getId();
    }

    @Override
    public void modify(Token token, Long id, ShopMovieModifyParam param) {
        token.validAnyAuthority(RoleEnum.Admin,RoleEnum.Manager,RoleEnum.ShopManager);
        ShopMovie entity = select(id);
        ErrorCode.RECORD_NOT_EXIST.assertNotNull(entity,id);
        if(!token.hasAuthority(RoleEnum.Admin)){
            ErrorCode.PROPERTY_CHECK_ERROR.assertEqual(entity.getOrgUnitId(),token.getOrgUnitId(),()->new Object[]{"剧本","不具备店铺剧本["+id+"]的访问权限"});
        }
        SimpleOrgUnitVo orgUnit = movieServiceInvoker.orgUnitInfo(entity.getOrgUnitId());
        ErrorCode.ORG_UNIT_NOT_EXIST.assertNotNull(orgUnit,entity.getOrgUnitId());
        ErrorCode.PROPERTY_CHECK_ERROR.assertTrue(orgUnit.shopType(), "组织","只能是店铺才能执行此操作");
        ErrorCode.PROPERTY_CHECK_ERROR.assertTrue(orgUnit.normalStatus(),"店铺","店铺已经下线");

        MovieVo movie = movieServiceInvoker.movieInfo(entity.getMovieId(),param.getMovieVersion());
        ErrorCode.MOVIE_NOT_EXIST.assertNotNull(movie,()->new Object[]{
                String.format("id:%d,version:%s",entity.getMovieId(),param.getMovieVersion())
        });
        ErrorCode.PROPERTY_CHECK_ERROR.assertTrue(movie.statusOnline(),"剧本","剧本已经下线");
        mapper.updateByParam(id, param);
    }

    @Override
    public void delete(@NotNull Token token, @NotNull Long id) {
        token.validAnyAuthority(RoleEnum.Admin,RoleEnum.Manager,RoleEnum.ShopManager);
        ShopMovie entity = select(id);
        ErrorCode.RECORD_NOT_EXIST.assertNotNull(entity,id);
        if(!token.hasAuthority(RoleEnum.Admin)){
            ErrorCode.PROPERTY_CHECK_ERROR.assertEqual(entity.getOrgUnitId(),token.getOrgUnitId(),()->new Object[]{"剧本","不具备店铺剧本["+id+"]的访问权限"});
        }
        delete(entity.getId());
    }

    @NotNull
    @Override
    public PageVo<ShopMovieVo> page(@NotNull PageParam pageParam, @NotNull SortParam sortParam, @NotNull ShopMovieListParam listParam) {
        String orderColumn = sortParam.orderColumn("playTimes");
        String order = sortParam.order();
        Page<ShopMovie> list = PageHelper.startPage(pageParam.getPage(),pageParam.getLimit());
        mapper.list(listParam.getOrgUnitId(), orderColumn,order,listParam);
        List<SimpleOrgUnitVo> orgUnits = movieServiceInvoker.orgUnits(list.stream().map(ShopMovie::getOrgUnitId).collect(Collectors.toSet()));
        List<MovieVo> latest = movieServiceInvoker.latestVersions(list.stream().map(ShopMovie::getMovieId).collect(Collectors.toSet()));
        List<MovieLevelVo> movieLevels = movieServiceInvoker.movieLevels();
        return page(list,mi->{
            ShopMovieVo vo = new ShopMovieVo();
            BeanUtils.copyProperties(mi,vo);
            vo.setTag(ShopMovieVo.showTag(mi.getTag()));
            MovieVo movie = IdOperators.find(latest, mi.getMovieId());
            if(movie != null ){  // 使用最新版本信息更新
                vo.setMovieName(movie.getName());
                vo.setAuthor(movie.getAuthor());
                vo.setBrief(movie.getBrief());
                vo.setMovieVersion(movie.getVersion());
                vo.setDuration(movie.getDuration());
                vo.setMinPlayers(movie.getMinPlayers());
                vo.setMaxPlayers(movie.getMaxPlayers());
                vo.setTag(movie.getTag());
            }
            SimpleOrgUnitVo orgUnit = IdOperators.find(orgUnits, mi.getOrgUnitId());
            if(orgUnit != null){
                vo.setOrgUnitName(orgUnit.getName());
            }
            MovieLevelVo level = IdOperators.find(movieLevels, mi.getMovieLevelId());
            if(level != null){
                vo.setPrice(level.getTodayPrice());
            }
            return vo;
        });
    }

    @Override
    public void online(@NotNull Token token, @Nullable Long id) {
        validAuth(token, id);
        update(id,"status", MovieVo.STATUS_ONLINE);
    }

    @Override
    public void offline(@NotNull Token token, @Nullable Long id) {
        validAuth(token, id);
        update(id,"status", MovieVo.STATUS_OFFLINE);
    }

    private void validAuth(@NotNull Token token, @Nullable Long id) {
        token.validAnyAuthority(RoleEnum.Admin, RoleEnum.Manager, RoleEnum.ShopManager);
        ShopMovie entity = select(id);
        ErrorCode.RECORD_NOT_EXIST.assertNotNull(entity,id);
        if(!token.hasAuthority(RoleEnum.Admin)){
            ErrorCode.PROPERTY_CHECK_ERROR.assertNotNull(token.getOrgUnitId(),"组织","用户所属组织为空");
            ErrorCode.MOVIE_ACCESS_DENIED.assertEqual(entity.getOrgUnitId(), token.getOrgUnitId(),entity.getMovieName());
        }
    }
}
